//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <iostream>
#include <fstream>

#include "ListAncestorMol.h"
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
#define NOFILTER1 1
#define NOFILTER2 1
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
using namespace std;
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
#define TYPE_COINCIDENCE 1
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
namespace SpaceCorelationClusters {

  bool AscendentAncestor(TNode <AncestorMol>* NodeT, void* ref, void* parameters) {
    AncestorMol* ancestorA  = NodeT->Info();
    AncestorMol* ancestorB  = ((TNode <AncestorMol>*)ref)->Info();
    int          level      = (*(int*)parameters) - 1;
    return (*(ancestorA->ListIdAncestor()->Get(level)) < *(ancestorB->ListIdAncestor()->Get(level)))?true:false;
  }

  bool DiffAncestor(TNode <AncestorMol>* NodeT, void* ref, void* parameters) {
    AncestorMol* ancestorA  = NodeT->Info();
    AncestorMol* ancestorB  = ((TNode <AncestorMol>*)ref)->Info();
    int          level      = (*(int*)parameters) - 1;
    if (*(ancestorA->ListIdAncestor()->Get(level)) != *(ancestorB->ListIdAncestor()->Get(level))) return false;
    else {
      if (*(ancestorA->ListIdAncestor()->Get(level)) == *(ancestorA->ListIdAncestor()->Get(0))) {
        NodeT->Info(NULL);
        NodeT->Info(ancestorB);
        ((TNode <AncestorMol>*)ref)->Info(NULL);
        ((TNode <AncestorMol>*)ref)->Info(ancestorA);
      }
      return true;
    }
  }

  bool EqualAncestor(TNode <AncestorMol>* NodeT, void* ref, void* parameters) {
    AncestorMol* ancestorA  = NodeT->Info();
    AncestorMol* ancestorB  = ((TNode <AncestorMol>*)ref)->Info();
    int          level      = (*(int*)parameters) - 1;
    return (*(ancestorA->ListIdAncestor()->Get(level)) == *(ancestorB->ListIdAncestor()->Get(level)))?true:false;
  }

};
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
int main(int argc, char** argv) {

  String* filenameCluster1In;
  String* filenameCluster2In;
  String* filenameOut;
  int     ancestorLevel1, ancestorLevel2;

  if (argc < 6) {
    cout << "Error in the input arguments. The execution must be: " << endl;
    cout << "./CorrelationClustersPlotComplete <Input Cluster File - 1> <#Ancestor Level - 1> <Input Cluster File - 2> <#Ancestor Level> <Output File>" << endl;
    return 0;
  }
  else {
    cout << "---------------------------------------------------------------------------------" << endl;
    cout << " Input Cluster File - 1 : " << argv[1] << endl;
    cout << "    #Ancestor Level - 1 : " << argv[2] << endl;
    cout << " Input Cluster File - 2 : " << argv[3] << endl;
    cout << "    #Ancestor Level - 2 : " << argv[4] << endl;
    cout << "            Output File : " << argv[5] << endl;
    cout << "---------------------------------------------------------------------------------" << endl;
    filenameCluster1In = new String(argv[1]);
    ancestorLevel1     = atoi(argv[2]);
    filenameCluster2In = new String(argv[3]);
    ancestorLevel2     = atoi(argv[4]);
    filenameOut        = new String(argv[5]);
  }

  ListAncestorMol* ancestorCluster1 = new ListAncestorMol();
  ListAncestorMol* ancestorCluster2 = new ListAncestorMol();

  ancestorCluster1->FilenameAncestor(filenameCluster1In);
  ancestorCluster2->FilenameAncestor(filenameCluster2In);

  ancestorCluster1->LoadDataAncestorFiles();
  ancestorCluster2->LoadDataAncestorFiles();

  fstream fileOut;
  fileOut.open(filenameOut->Out(), fstream::out);

  for (int i = 0; i < 155; i++) { fileOut << "-"; cout << "-";  }
  cout << endl; fileOut << endl;
  
  fileOut.width(10); fileOut.right; fileOut << "Level" << " |";
  fileOut.width(10); fileOut.right; fileOut << "Number" << " |";
  fileOut.width(20); fileOut.right; fileOut << "Representative" << " |";
  fileOut.width(10); fileOut.right; fileOut << "Size" << " |";
  fileOut.width(10); fileOut.right; fileOut << "Common" << " |";
  fileOut.width(10); fileOut.right; fileOut << "Level" << " |";
  fileOut.width(10); fileOut.right; fileOut << "Number" << " |";
  fileOut.width(25); fileOut.right; fileOut << "Repre. Other Cluster" << " |";
  fileOut.width(10); fileOut.right; fileOut << "Found" << " |";
  fileOut.width(20); fileOut.right; fileOut << "Ratio" << " |";
  fileOut << endl;

  cout.width(10); cout.right; cout << "Level" << " |";
  cout.width(10); cout.right; cout << "Number" << " |";
  cout.width(20); cout.right; cout << "Representative" << " |";
  cout.width(10); cout.right; cout << "Size" << " |";
  cout.width(10); cout.right; cout << "Common" << " |";
  cout.width(10); cout.right; cout << "Level" << " |";
  cout.width(10); cout.right; cout << "Number" << " |";
  cout.width(25); cout.right; cout << "Repre. Other Cluster" << " |";
  cout.width(10); cout.right; cout << "Found" << " |";
  cout.width(20); cout.right; cout << "Ratio" << " |";
  cout << endl;

  for (int i = 0; i < 155; i++) { fileOut << "-"; cout << "-";  }
  cout << endl; fileOut << endl;

  TListE <AncestorMol> *representativeAncestorList  = new TListE <AncestorMol>;
  TListE <AncestorMol> *representativeAncestorList2 = new TListE <AncestorMol>;

  ancestorCluster1->ListAncestor()->RepresentativeOcurrencesAfterOrdered(SpaceCorelationClusters::DiffAncestor, representativeAncestorList,  &ancestorLevel1);
  ancestorCluster2->ListAncestor()->RepresentativeOcurrencesAfterOrdered(SpaceCorelationClusters::DiffAncestor, representativeAncestorList2, &ancestorLevel2);

  int    counterCluster = 0;

  //cout << representativeAncestorList->Length() << endl;

  if (representativeAncestorList->Length()) {

    representativeAncestorList->SetInitial();

    while (representativeAncestorList->SetNext()) {

      //cout << "Repre: " << representativeAncestorList->GetCurrent()->ListIdAncestor()->Get(0)->Out() << endl;

      TListE <AncestorMol> *clusterList1 = new TListE <AncestorMol>;
      TListE <AncestorMol> *clusterList2 = new TListE <AncestorMol>;

      ancestorCluster1->ListAncestor()->AllOcurrence(SpaceCorelationClusters::EqualAncestor, clusterList1, representativeAncestorList->GetCurrentNode(), &ancestorLevel1);

      int clusterLengthSearch = clusterList1->Length();

      //cout << "Size: " << clusterList1->Length() << endl;

      clusterList1->SetInitial();

      while (clusterList1->SetNext()) {

        int levelSearch = 1;
        //cout << "Search: " << clusterList1->GetCurrent()->ListIdAncestor()->Get(levelSearch - 1)->Out() << endl;
        AncestorMol* resultSearch = ancestorCluster2->ListAncestor()->FirstOcurrence(SpaceCorelationClusters::EqualAncestor, clusterList1->GetCurrentNode(), &levelSearch);

        if (resultSearch) {
          //cout << "Found: " << resultSearch->ListIdAncestor()->Get(0)->Out() << endl;
          clusterList2->Add(resultSearch);
        }
        else {
          clusterLengthSearch--;
          //cout << "Error search the item: " << clusterList1->GetCurrent()->ListIdAncestor()->Get(0)->Out() << endl;
        }
        
      }

      clusterList2->QuickSortList(SpaceCorelationClusters::AscendentAncestor, NULL, &ancestorLevel2);

      int     sizeCoincidence = 0;
      String  compare;

      String  compareT, repreT;
      int     ancestorLevel1T, ancestorLevel2T;
      int     cluster1LengthT, cluster2LengthT;
      int     counterClusterT, sizeCoincidenceT = 0;
      int     positionAncestorT;
      double  ratioT;

      compare.In("");
      counterCluster++;

      //cout << "Other Length: " << clusterList2->Length() << endl;

      clusterList2->SetInitial();

      while (clusterList2->SetNext()) {

        //cout << clusterList2->GetCurrent()->ListIdAncestor()->Get(0)->Out() << "-" << clusterList2->GetCurrent()->ListIdAncestor()->Get(1)->Out() << "-" << clusterList2->GetCurrent()->ListIdAncestor()->Get(ancestorLevel - 1)->Out() << endl;

        if (strcmp(clusterList2->GetCurrent()->ListIdAncestor()->Get(ancestorLevel2 - 1)->Out(), compare.Out())) {
            
          if (compare.Length()) {

            representativeAncestorList2->SetInitial();

            int positionAncestor2 = 0;

            while (representativeAncestorList2->SetNext()) {
              if (!strcmp(compare.Out(), representativeAncestorList2->GetCurrent()->ListIdAncestor()->Get(ancestorLevel2 - 1)->Out()))
                break;
              positionAncestor2++;
            }

            double ratio = (clusterList2->Length())?((double)((double)sizeCoincidence/(double)clusterList2->Length())):0;

            if (sizeCoincidence > sizeCoincidenceT) {
              sizeCoincidenceT  = sizeCoincidence;
              counterClusterT   = counterCluster;
              repreT.In(representativeAncestorList->GetCurrent()->ListIdAncestor()->Get(0)->Out());
              cluster1LengthT   = clusterList1->Length();
              cluster2LengthT   = clusterList2->Length();
              positionAncestorT = positionAncestor2;
              compareT.In(compare.Out());
              sizeCoincidenceT  = sizeCoincidence;
              ratioT            = ratio;
            }

//            if (NOFILTER1 || ((ratio >= 0.5) && (sizeCoincidence > 1)) || sizeCoincidence >= 5) {
//
//              fileOut.width(10); fileOut.right; fileOut << ancestorLevel1 << " |";
//              fileOut.width(10); fileOut.right; fileOut << counterCluster << " |";
//              fileOut.width(20); fileOut.right; fileOut << representativeAncestorList->GetCurrent()->ListIdAncestor()->Get(0)->Out() << " |";
//              fileOut.width(10); fileOut.right; fileOut << clusterList1->Length() << " |";
//              fileOut.width(10); fileOut.right; fileOut << clusterList2->Length() << " |";
//              fileOut.width(10); fileOut.right; fileOut << ancestorLevel2 << " |";
//              fileOut.width(10); fileOut.right; fileOut << positionAncestor2 << " |";
//              fileOut.width(25); fileOut.right; fileOut << compare.Out() << " |";
//              fileOut.width(10); fileOut.right; fileOut << sizeCoincidence << " |";
//              fileOut.width(20); fileOut.right; fileOut << ratio << " |";
//              fileOut << endl;
//
//              cout.width(10); cout.right; cout << ancestorLevel1 << " |";
//              cout.width(10); cout.right; cout << counterCluster << " |";
//              cout.width(20); cout.right; cout << representativeAncestorList->GetCurrent()->ListIdAncestor()->Get(0)->Out() << " |";
//              cout.width(10); cout.right; cout << clusterList1->Length() << " |";
//              cout.width(10); cout.right; cout << clusterList2->Length() << " |";
//              cout.width(10); cout.right; cout << ancestorLevel2 << " |";
//              cout.width(10); cout.right; cout << positionAncestor2 << " |";
//              cout.width(25); cout.right; cout << compare.Out() << " |";
//              cout.width(10); cout.right; cout << sizeCoincidence << " |";
//              cout.width(20); cout.right; cout << ratio << " |";
//              cout << endl;
//
//            }

          }

          compare.In(clusterList2->GetCurrent()->ListIdAncestor()->Get(ancestorLevel2 - 1)->Out());
          sizeCoincidence = 0;

        }
        sizeCoincidence++;
      }

      representativeAncestorList2->SetInitial();

      int positionAncestor2 = 0;

      while (representativeAncestorList2->SetNext()) {
        if (!strcmp(compare.Out(), representativeAncestorList2->GetCurrent()->ListIdAncestor()->Get(ancestorLevel2 - 1)->Out()))
          break;
        positionAncestor2++;
      }

      double ratio = (clusterList2->Length())?((double)((double)sizeCoincidence/(double)clusterList2->Length())):0;
      
      if (sizeCoincidence > sizeCoincidenceT) {
        sizeCoincidenceT  = sizeCoincidence;
        counterClusterT   = counterCluster;
        repreT.In(representativeAncestorList->GetCurrent()->ListIdAncestor()->Get(0)->Out());
        cluster1LengthT   = clusterList1->Length();
        cluster2LengthT   = clusterList2->Length();
        positionAncestorT = positionAncestor2;
        compareT.In(compare.Out());
        sizeCoincidenceT  = sizeCoincidence;
        ratioT            = ratio;
      }

      if (sizeCoincidenceT > 1) {
          
        fileOut.width(10); fileOut.right; fileOut << ancestorLevel1 << " |";
        fileOut.width(10); fileOut.right; fileOut << counterClusterT << " |";
        fileOut.width(20); fileOut.right; fileOut << repreT.Out() << " |";
        fileOut.width(10); fileOut.right; fileOut << cluster1LengthT << " |";
        fileOut.width(10); fileOut.right; fileOut << cluster1LengthT << " |";
        fileOut.width(10); fileOut.right; fileOut << ancestorLevel2 << " |";
        fileOut.width(10); fileOut.right; fileOut << positionAncestorT << " |";
        fileOut.width(25); fileOut.right; fileOut << compareT.Out() << " |";
        fileOut.width(10); fileOut.right; fileOut << sizeCoincidenceT << " |";
        fileOut.width(20); fileOut.right; fileOut << ratioT << " |";
        fileOut << endl;

        cout.width(10); cout.right; cout << ancestorLevel1 << " |";
        cout.width(10); cout.right; cout << counterClusterT << " |";
        cout.width(20); cout.right; cout << repreT.Out() << " |";
        cout.width(10); cout.right; cout << cluster1LengthT << " |";
        cout.width(10); cout.right; cout << cluster2LengthT << " |";
        cout.width(10); cout.right; cout << ancestorLevel2 << " |";
        cout.width(10); cout.right; cout << positionAncestorT << " |";
        cout.width(25); cout.right; cout << compareT.Out() << " |";
        cout.width(10); cout.right; cout << sizeCoincidenceT << " |";
        cout.width(20); cout.right; cout << ratioT << " |";
        cout << endl;

      }
      
//      if (NOFILTER1 || ((ratio >= 0.5) && (sizeCoincidence > 1)) || sizeCoincidence >= 5) {
//
//        fileOut.width(10); fileOut.right; fileOut << ancestorLevel1 << " |";
//        fileOut.width(10); fileOut.right; fileOut << counterCluster << " |";
//        fileOut.width(20); fileOut.right; fileOut << representativeAncestorList->GetCurrent()->ListIdAncestor()->Get(0)->Out() << " |";
//        fileOut.width(10); fileOut.right; fileOut << clusterList1->Length() << " |";
//        fileOut.width(10); fileOut.right; fileOut << clusterList2->Length() << " |";
//        fileOut.width(10); fileOut.right; fileOut << ancestorLevel2 << " |";
//        fileOut.width(10); fileOut.right; fileOut << positionAncestor2 << " |";
//        fileOut.width(25); fileOut.right; fileOut << compare.Out() << " |";
//        fileOut.width(10); fileOut.right; fileOut << sizeCoincidence << " |";
//        fileOut.width(20); fileOut.right; fileOut << ratio << " |";
//        fileOut << endl;
//
//        cout.width(10); cout.right; cout << ancestorLevel1 << " |";
//        cout.width(10); cout.right; cout << counterCluster << " |";
//        cout.width(20); cout.right; cout << representativeAncestorList->GetCurrent()->ListIdAncestor()->Get(0)->Out() << " |";
//        cout.width(10); cout.right; cout << clusterList1->Length() << " |";
//        cout.width(10); cout.right; cout << clusterList2->Length() << " |";
//        cout.width(10); cout.right; cout << ancestorLevel2 << " |";
//        cout.width(10); cout.right; cout << positionAncestor2 << " |";
//        cout.width(25); cout.right; cout << compare.Out() << " |";
//        cout.width(10); cout.right; cout << sizeCoincidence << " |";
//        cout.width(20); cout.right; cout << ratio << " |";
//        cout << endl;
//
//      }

      clusterList1->TransferAll();
      clusterList2->TransferAll();

      if (clusterList1)         delete clusterList1;
      if (clusterList2)         delete clusterList2;

    }

    representativeAncestorList->TransferAll();
    representativeAncestorList2->TransferAll();

    if (representativeAncestorList)  delete representativeAncestorList;
    if (representativeAncestorList2) delete representativeAncestorList2;

  }

  fileOut.close();
  
  if (ancestorCluster1) delete ancestorCluster1;
  if (ancestorCluster2) delete ancestorCluster2;

  for (int i = 0; i < 155; i++) cout << "-"; cout << endl;
  

  return 1;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//




